Skip to content

release: check the nvx package and declare the breaking release (SL8.1) - #1561

Merged
Pedro Henrique Penna (ppenna) merged 3 commits into
feature/nvx-refactorfrom
agents/slim-sl8-1-release
Nov 13, 2026
Merged

Pedro Henrique Penna (ppenna) merged 3 commits into
feature/nvx-refactorfrom
agents/slim-sl8-1-release

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Part of #1132 (SL8.1: The breaking release is published).

The release's version is 0.2.0-alpha.1, as decided on #1132 (#1132 (comment)).

What and why

The breaking release of #1076 needs its changelog and version, CI checks that its package and public API are the planned ones, and a standalone install of the guest tools from the package. This PR prepares that release; it publishes nothing. The full run of dev that first packs a commit containing it publishes nvx at the declared version, with the existing publishing jobs, after Pedro Henrique Penna (@ppenna) merges feature/nvx-refactor into dev.

  1. scripts: check that the public API hides one main per binary. public_api.py compared the API with its snapshots, hidden items marked, but not which items may be hidden. It now reads each [[bin]] target's code, from cargo metadata, outside its comments, which nest, and its string, byte string, C string, raw string and character literals, for the single nvx::…::main() that the binary calls. It fails, with or without --update, unless the hidden items of both platforms' listings are exactly those functions and the modules that hold them: a binary that calls none or several, or whose delegation a comment holds, two binaries that share one, a main that no listing hides, a main that a listing shows without hiding it, and any other hidden item fail. The current snapshots pass: their hidden items are the 12 binaries' mains and their modules. The nvx-rs job runs it in every pull request and in the full run of dev, whose Required status check gates the crate jobs.
  2. scripts: install nvx-ingress from the crate's package before publishing. Package nvx crate (publish_nvx_crate.py package) checked and built the package with every feature only. It now also requires the public API's snapshots in the package, so its users can check the surface that it promises, and, after the all-features build, runs cargo install --locked --path <unpacked package> --no-default-features --features guest --profile guest --bin nvx-ingress --root … from its work directory, $RUNNER_TEMP/nvx-crate, outside the checkout, then runs the installed nvx-ingress test on a snapshot without sockets, which must print 0 4e56584c01000000 (NVXL's NONE vector). A failure fails the job, so Publish nvx crate publishes nothing. The job already holds no right to publish.
  3. nvx-rs: declare 0.2.0-alpha.1, the breaking release, and its changelog. A root CHANGELOG.md with one entry lists the breaking changes, each checked against the code and the public API snapshots, and links doc/migrate-from-alpha.7.md. The release also corrects the crate's description in nvx-rs/Cargo.toml, because crates.io displays it with each version: it named the OpenVMM control protocol, policy lowering, and the supervision of NVX microVMs, which nvx-rs slimming workstream: make nvx a library of mechanisms and value types #1076 made private or removed, and now names the library's mechanisms and value types, as nvx-rs/README.md describes them. No test or check reads the description; the package checks read only the name and the version. Every document that names the crate's versions follows the new series: doc/distribution.md's description of the crate and the version that its install of the guest tools names, doc/ci.md's description of the nightly versions, and the version requirements of nvx-rs/README.md; doc/migrate-from-alpha.7.md already pins 0.2.0-alpha.1.

CI's publishing jobs need no change: with 0.2.0-alpha.1 declared, plan_release sees nvx-rs/ changed since the newest version's commit on dev, and next_version takes the declared number of the new series, which sorts above every 0.1.0-alpha.N, so the first full run publishes exactly 0.2.0-alpha.1, and later nightlies 0.2.0-alpha.2 and on. Only nvx is published, as before.

Measured: 147 core lines, in 4 counted files (scripts/public_api.py 88, scripts/nvx_tools/crate_release.py 55, scripts/publish_nvx_crate.py 2, nvx-rs/Cargo.toml 2); the estimate is 80, the stop 160. BOOT_CONTRACT_VERSION and CONTROL_CONTRACT_REVISION are unchanged. The public API is unchanged; its snapshots need no update.

Old tests of the area: every test of scripts/test_crate_release.py and scripts/test_public_api.py is kept; the workflow tests of scripts/test_nvx_tools.py are kept unchanged, since the workflow does not change. The case matrix's rows of Check the public API, crate-package and crate-release describe the new checks, as kept.

Validation

At bc6f29938b2, on ecd6e02d85f:

  • On nvx-mshv-test (Linux): the validate-nvx unit tests, 1814 OK (38 skipped), scripts/test_adversarial.py and the nvx.py … --help checks: OK. python3 scripts/public_api.py: passes.
  • cargo package --list --locked (nvx-mshv-test): 516 files, the 514 that Git tracks in nvx-rs/, with .cargo_vcs_info.json and Cargo.toml.orig; among them public-api/linux.txt and public-api/windows.txt.
  • cargo publish --dry-run --locked (nvx-mshv-test): packaged 516 files, 7.8 MiB (1.8 MiB compressed), verified, "aborting upload due to dry run". Nothing was published, and no tag was pushed.
  • python3 scripts/publish_nvx_crate.py package --work-dir /mnt/data/ppenna/nvx-sl8-1-crate with RUSTUP_TOOLCHAIN=1.95.0, as Package nvx crate runs it (nvx-mshv-test, which queries crates.io read-only and never publishes): "nvx-rs/ changed since f7720fb, from which nvx 0.1.0-alpha.16 was packed: packing nvx 0.2.0-alpha.1", checked the 516 files, built with every feature, installed nvx-ingress with the guest profile from the unpacked package and ran it, exit 0 in 40 s; package SHA-256 7455c26fa1a8267beb8d5f577cc3e8a5c11d050d30cfa6475cae929f48852e0d.
  • Standalone installs from that nvx-0.2.0-alpha.1.crate, unpacked outside any repository on nvx-mshv-test: cargo install --path nvx-0.2.0-alpha.1 --no-default-features --features guest --profile guest --bin nvx-ingress (no --locked, fresh resolution) gave a glibc executable, and --locked --target x86_64-unknown-linux-musl a static-pie one; each printed 0 4e56584c01000000 for an empty snapshot, 0 4e56584c0100000106011f90 for one TCP listener on port 8080, and exited 2 without arguments.
  • On Windows: the validate-nvx unit tests, 1814 OK (73 skipped), scripts/test_adversarial.py, the nvx-host-connect tests and the nvx.py … --help checks: OK. python scripts/public_api.py: passes.
  • check_markdown_links.py: passes, CHANGELOG.md's link to the migration guide included. Ruff check and format: clean; Pyright strict for Linux and Windows: clean. check_test_layout.py: passes. The case matrix check (check_matrix.py … 99d2022085f): passes.

Test changes (check_test_changes.py --base origin/feature/nvx-refactor: 6 changes to existing tests, 11 added; label tests-modified):

  • CRATE_FILES: the demo crate holds the two API snapshots, which a package must now hold.
  • _Cargo.__init__, _Cargo.__call__, _Cargo.reset: the fake Cargo also takes cargo install, and records each command's directory; _Cargo.capture, new, runs the installed tool with a result that a test sets, and Git for real.
  • ReleaseTests.package: patches run_capture with that fake too.
  • ReleaseTests.test_the_first_version_is_the_declared_one: expects the install and the tool's run after the build.
  • Added: test_the_package_job_installs_and_runs_the_guest_tool_of_the_package, test_a_guest_tool_that_does_not_run_as_it_should_publishes_nothing, test_a_package_must_hold_the_snapshots_of_its_public_api, ChangelogTests.test_the_newest_entry_is_the_series_that_the_crate_declares, and EntryPointTests in scripts/test_public_api.py, with test_finds_no_call_in_a_comment_or_a_literal and test_hides_an_entry_point_on_every_platform_that_lists_it.

@ppenna Pedro Henrique Penna (ppenna) added tests-modified Changes existing tests, test data, or test wiring feat-nvx-refactor labels Nov 12, 2026
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 6 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests.

Test code

Change What Before After
modified helper assignment CRATE_FILES in scripts/test_crate_release.py scripts/test_crate_release.py:70 scripts/test_crate_release.py:71
modified helper def _Cargo.__init__ in scripts/test_crate_release.py scripts/test_crate_release.py:268 scripts/test_crate_release.py:272
modified helper def _Cargo.__call__ in scripts/test_crate_release.py scripts/test_crate_release.py:279 scripts/test_crate_release.py:286
modified helper def _Cargo.reset in scripts/test_crate_release.py scripts/test_crate_release.py:315 scripts/test_crate_release.py:346
modified helper def ReleaseTests.package in scripts/test_crate_release.py scripts/test_crate_release.py:917 scripts/test_crate_release.py:962
modified test def ReleaseTests.test_the_first_version_is_the_declared_one in scripts/test_crate_release.py scripts/test_crate_release.py:971 scripts/test_crate_release.py:1019

Relocated unchanged: 0; added: 11. Compared the merge base ecd6e02d85fe with bc6f29938b26.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The API gate counts calls in comments and string literals, allowing a binary with commented-out delegation to pass despite never calling a library entry point.

1 open issue
What changed in this PR

This PR prepares NVX’s breaking prerelease using the existing release pipeline; it does not publish a release itself. The proposed version, 0.2.0-alpha.1, remains provisional.

Changes:

  • Checks that hidden public API items correspond to binary entry points and their containing modules.
  • Requires packaged API snapshots and installs and runs nvx-ingress from the unpacked crate outside the checkout.
  • Declares the release version, adds its breaking-change changelog, and updates documentation and tests.
File Description
scripts/​test_public_api.py Tests entry-point discovery and hidden API validation.
scripts/​test_crate_release.py Tests package contents, guest-tool checks, and changelog version alignment.
scripts/​publish_nvx_crate.py Updates help and documentation for the install check.
scripts/​public_api.py Adds binary entry-point and hidden API checks.
scripts/​nvx_tools/​crate_release.py Requires API snapshots and validates a standalone guest-tool install.
nvx-rs/​Cargo.toml Declares the provisional release version.
nvx-rs/​Cargo.lock Aligns the crate’s locked version.
doc/​distribution.md Documents the new prerelease series.
doc/​contribute.md Explains the hidden entry-point requirement.
doc/​ci.md Documents package and API validation.
doc/​acceptance-case-matrix.md Records the expanded checks in existing CI cases.
CHANGELOG.md Lists breaking changes and links the migration guide.

Review effort: Balanced

Comment thread scripts/public_api.py Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The API checker can miss a Windows-exposed entry point when Linux hides it and can mistake text inside raw C strings for a real delegation call, allowing invalid API snapshots to pass.

2 open issues
1 resolved since last review

Review effort: Balanced

Comment thread scripts/public_api.py Resolved
Comment thread scripts/public_api.py Resolved
The breaking release's public API must hold exactly the planned
surface and one hidden main per binary (#1132): NVX's programs live
in nvx, private to it, and each binary calls a #[doc(hidden)] main,
the only public item that a program adds (#1076). public_api.py
checked that the API matches its snapshots, hidden items marked, but
not which items may be hidden, so a program's other items, or a
binary whose entry point is public, could reach the API unnoticed.

The script now also finds each binary's entry point, the function
main of nvx that the binary's code calls, such as
nvx::host::cli::main for nvx-rs, from the targets that cargo
metadata lists. It reads the code outside the source's comments,
which nest, and its string, byte string, C string, raw string, and
character literals, so that a call that a comment or a literal holds
counts for none. It fails, with or without --update, unless the
API's hidden items, over both platforms' listings, are those
functions and the modules that hold them: when a binary calls no
such function or several, when two binaries call one, when no
listing hides a binary's main, when a listing shows one without
hiding it, or when the API hides anything else. A guest program's
main is hidden on Linux alone, since its binary is a stub elsewhere,
but no platform may list an entry point unhidden. The current
snapshots pass: their hidden items are the 12 binaries' mains and the
modules that hold them.

The nvx-rs job runs the check in every pull request and in the full
run of dev that publishes the crate, whose Required status check
requires that job, so the release's snapshots are checked too.
doc/ci.md and doc/contribute.md describe the rule, and the case
matrix's row of the public API check names it.

Tests: test_public_api.py's EntryPointTests find the main that each
binary calls, skipping a guest stub's, refuse a binary that calls
none or two, or whose delegation a comment holds, find no call in
line, doc, nested block comments, or string, raw string, byte string,
C string and raw C string literals, and keep the code after a comment
or a literal that holds a quote, and a lifetime. They accept hidden
mains and their modules, also when a module holds public items, and
report another hidden item, a public main, a main that one platform
hides and another lists unhidden, and a main that two binaries share.

Part of #1132 (SL8.1).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The breaking release must let users install and run the guest tools
from the package alone (#1132): outside any checkout,
cargo install nvx --no-default-features --features guest
--profile guest --bin nvx-ingress, then nvx-ingress. Package nvx
crate packed the crate, checked the package against the commit, and
built it with every feature, but never with the guest feature alone
or the guest profile, and never from outside the repository, so a
package that only the checkout's build could complete, such as one
that lost a file of the guest's code path or the guest profile,
could still be published.

The package job now also installs nvx-ingress from the package's
files, the directory that its build unpacked, with cargo install
--locked --path, --no-default-features --features guest and
--profile guest, into the job's work directory, from which it runs
Cargo, $RUNNER_TEMP/nvx-crate in CI, outside the checkout. Then it
runs the installed program's test mode on a snapshot of the socket
tables that holds no socket, which must print one scan at time 0
that announces no listener, the NVXL conformance vector NONE. A
failure fails the job, which then outputs no version, so Publish nvx
crate publishes nothing. The job already held no right to publish,
so the build scripts and procedural macros of this build cannot
publish either.

The package must now also hold the public API's snapshots, with which
its users check the API that it promises; the nvx-rs job, which
Required status check requires, checks them in the same run. The
publish job's check of the package requires them too.

doc/ci.md's crates.io releases and the case matrix's rows of the two
crate jobs describe the new checks, and the scripts' docstrings the
package job's steps.

Tests: test_crate_release.py's fake Cargo also takes cargo install,
and runs the installed tool, whose output a test sets.
test_the_package_job_installs_and_runs_the_guest_tool_of_the_package
checks the install's command, its directory, outside the checkout,
the snapshot and the run; a tool that fails or prints another
announcement publishes nothing; and a package without either
snapshot fails its check. The demo crate of the tests holds
snapshots, and test_the_first_version_is_the_declared_one expects
the install and the run after the build.

Part of #1132 (SL8.1).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The breaking release of #1076 must declare its version and record
what it breaks (#1132). crates.io holds 0.1.0-alpha.1 to
0.1.0-alpha.16, and dev's nightly runs take the next number of the
0.1.0-alpha series whenever the crate changes there, until this work
reaches dev. The crate now declares 0.2.0-alpha.1, as #1132 decided,
the first version of a series that nothing has published, which
doc/distribution.md describes for a new series: the full run of dev
that first packs this commit publishes exactly that version, whatever
numbers the nightlies took meanwhile, and a requirement such as
nvx = "0.1.0-alpha.7", which Cargo also resolves to later 0.1.0
pre-releases, never resolves to it.

The release also corrects the crate's description, which crates.io
displays with each version: it named the OpenVMM control protocol,
policy lowering, and the supervision of NVX microVMs, which #1076
made private or removed. It now names the library's mechanisms and
value types, as nvx-rs/README.md describes them. No check reads it.

The new root CHANGELOG.md records the release in one entry, which
lists its breaking changes and links doc/migrate-from-alpha.7.md for
the details. The documents that name the crate's versions follow the
new series: doc/distribution.md's description of the crate and the
version that its install of the guest tools names, doc/ci.md's
description of the nightly versions, and the version requirements of
nvx-rs/README.md, which name 0.2.0-alpha.1 and the nightly
0.2.0-alpha.2 in place of 0.1.0-alpha.4.

Tests: ChangelogTests keeps the changelog's newest entry equal to the
version that nvx-rs/Cargo.toml declares, so a pull request that starts
another series adds its entry.

Part of #1132 (SL8.1).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain in the release-preparation changes.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) merged commit 05cb371 into feature/nvx-refactor Nov 13, 2026
87 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/slim-sl8-1-release branch November 13, 2026 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat-nvx-refactor tests-modified Changes existing tests, test data, or test wiring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants